﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Timers;

namespace MathTools
{
    public class NewtonMethod
    {
        #region Types

        delegate ICollection<double[]> SolveEquation( ICalculateData data );

        #endregion

        #region Fields

        private bool m_isRun = true;

        private const double m_minFitness = 1e-5;

        private const double m_maxFitness = 1e+5;

        private readonly ICalculateData m_data;
        
        private SolveEquation m_solver;
        private IAsyncResult m_solverResult;

        private ICollection<double[]> m_answers;

        #endregion

        public NewtonMethod( ICalculateData data )
        {
            m_data = data;

            m_solver = new SolveEquation( this.calculate );
        }

        /// <summary>
        /// Останавливает выполнение, запущенное в асинхронном режиме.
        /// </summary>
        public void stop()
        {
            m_isRun = false;
        }

       // public void 
        /// <summary>
        /// Возвращает значение 0..1000
        /// </summary>
        public int Progress
        {
            get
            {
                return (int)( 1000 - m_data.Fitness / m_minFitness );
            }
        }

        public bool runAsynchronly()
        {
            m_solverResult = m_solver.BeginInvoke( m_data, new AsyncCallback( this.callBack ), null );
            
            return true;
        }

        private void callBack( IAsyncResult result )
        {
            m_isRun = false;

            m_answers = m_solver.EndInvoke( result );
        }

        /// <summary>
        /// Возвращает ответ или null, если он еще не был получен
        /// </summary>
        /// <returns></returns>
        public ICollection<double[]> Answer
        {
            get
            {
                if( m_isRun )
                    return null;

                return m_answers;
            }
        }

        ICollection<double[]> calculate( ICalculateData input )
        {
            m_answers = new List< double[] >();

            while( input.Fitness > m_minFitness )
            {
                m_answers.Add( input.nextVector );
            }

            return m_answers;
        }

    }
}
